﻿using Instances;
using NLog;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;

namespace Com.Lancetinc.Evs.Helpers
{
    public static class VideoHelper
    {
        private static readonly ILogger Logger = LogManager.GetCurrentClassLogger();

        #region Join

        private static string _ffmpegExePath = Path.Combine(DirUtil.ExeDirectory, "ffmpeg.exe");
        private static string _lockFile = "ffmpeg.lock";
        /// <summary>
        /// 合并多个线程
        /// 直接调用ffmpeg.exe命令行的形式实现
        /// 如果有问题请切换到FFMpegCore
        /// </summary>
        /// <param name="output"></param>
        /// <param name="inputs"></param>
        /// <returns></returns>
        public static bool Join(string output, params string[] inputs)
        {
            if (!File.Exists(_ffmpegExePath))
            {
                Logger.Warn("ffmpeg.exe not exists");
                return false;
            }

            var dir = Path.GetDirectoryName(inputs[0]);
            var ext = Path.GetExtension(inputs[0]);

            var lockFile = Path.Combine(dir, _lockFile);
            if (File.Exists(lockFile))
                return false;

            var tmpFile = Path.Combine(dir, "tmp" + ext);
            if (File.Exists(tmpFile))
                FileUtil.Delete(tmpFile);

            try
            {
                using var _ = File.Open(lockFile, FileMode.OpenOrCreate);
                if (!JoinCore(tmpFile, inputs))
                {
                    return false;
                }

                File.Copy(tmpFile, output, true);
                // 删除输入的文件
                foreach (var fileToDel in inputs.Where(x => !x.Equals(output, StringComparison.OrdinalIgnoreCase)))
                {
                    FileUtil.Delete(fileToDel);
                }

                return true;
            }
            catch (Exception exc)
            {
                Logger.Error(exc);
            }
            finally
            {
                FileUtil.Delete(lockFile);
                FileUtil.Delete(tmpFile);
            }

            return false;
        }

        private static bool JoinCore(string output, params string[] inputs)
        {
            var dir = Path.GetDirectoryName(inputs[0]);
            var listFile = Path.Combine(dir, "list.txt");
            try
            {
                CreateCommandList(listFile, inputs);
                var cmd = GenerateCommand(listFile, output);
                var startInfo = new ProcessStartInfo(_ffmpegExePath, cmd);
                var args = new ProcessArguments(startInfo);
                var process = args.Start();
                var result = process.WaitForExit();
                return result.ExitCode == 0;
            }
            catch (Exception exc)
            {
                Logger.Error(exc);
            }
            finally
            {
                FileUtil.Delete(listFile);
            }

            return false;
        }

        private static string GenerateCommand(string listFile, string targetVideo)
        {
            return $"-f concat -safe 0 -i \"{listFile}\" -c copy \"{targetVideo}\"";
        }

        private static void CreateCommandList(string listFile, string[] inputs)
        {
            var lines = new List<string>();
            foreach (var input in inputs)
            {
                lines.Add($"file '{input}'");
            }

            File.WriteAllLines(listFile, lines);
        }
        #endregion
    }
}